﻿#include "ScreenShotWidget.h"
#include "QyMultiMedia/MediaCommon.h"
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QClipboard>
#include <QFileDialog>
#include "YMagnifier.h"
#include "Tools.h"
#include "DrawTools.h"
#include "Yuan.h"
#include "StickyNote.h"
#include "MediaTools.h"
#include "YImageDrawer.h"

ScreenShotWidget::ScreenShotWidget(QWidget *parent) :
    QWidget(parent),
    magn(new YMagnifier),
    tools(new Tools),
    drawTools(new DrawTools)
{
    image = MediaCommon::grabWindow();
    magn->setImage(image);

    move(0, 0);
    setFixedSize(image.size());
    setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);

    setFocusPolicy(Qt::StrongFocus);
    setMouseTracking(true);
    show();
    activateWindow();
    setFocus();
//    setCursor(Qt::CrossCursor);
    setCursor(Yuan::CustomCursor());
    update();
    magn->set(QCursor::pos());
    magn->raise();

    connect(magn, &YMagnifier::keyClicked, [this](const Qt::Key& key){
        QKeyEvent keyEvent(QKeyEvent::KeyRelease, key, Qt::NoModifier);
        keyReleaseEvent(&keyEvent);
    });

    outside.resize(4);
    edge.resize(4);
    corner.resize(4);

    initToolConnect();
}

ScreenShotWidget::~ScreenShotWidget()
{
    delete magn;
    delete tools;
    delete drawTools;
}

void ScreenShotWidget::refreshScreenShotArea()
{
    if(screenShotArea.isValid()){
        outside[0] = QRect(rect().topLeft(), QSize(screenShotArea.x(), screenShotArea.y() + screenShotArea.height()));
        outside[1] = QRect(QPoint(screenShotArea.x(), rect().y()), QSize(rect().width() - screenShotArea.x(), screenShotArea.y()));
        outside[2] = QRect(QPoint(screenShotArea.right() + 1, screenShotArea.y()), QSize(rect().width() - screenShotArea.right(), screenShotArea.height()));
        outside[3] = QRect(QPoint(rect().x(), screenShotArea.bottom() + 1), rect().bottomRight());

        edge[0] = QRect(screenShotArea.x() + screenShotArea.width() / 2 - 2, screenShotArea.y() - 2, 5, 5);
        edge[1] = QRect(screenShotArea.x() + screenShotArea.width() / 2 - 2, screenShotArea.bottom() - 1, 5, 5);
        edge[2] = QRect(screenShotArea.x() - 2, screenShotArea.bottom() - 2 - screenShotArea.height() / 2, 5, 5);
        edge[3] = QRect(screenShotArea.right() - 1, screenShotArea.bottom() - 2 - screenShotArea.height() / 2, 5, 5);

        corner[0] = QRect(screenShotArea.topLeft() - QPoint(2, 2), QSize(5, 5));
        corner[1] = QRect(screenShotArea.topRight() - QPoint(1, 2), QSize(5, 5));
        corner[2] = QRect(screenShotArea.bottomLeft() - QPoint(2, 1), QSize(5, 5));
        corner[3] = QRect(screenShotArea.bottomRight() - QPoint(1, 1), QSize(5, 5));
    }else if(expectArea.isValid()){
        outside[0] = QRect(rect().topLeft(), QSize(expectArea.x(), expectArea.y() + expectArea.height()));
        outside[1] = QRect(QPoint(expectArea.x(), rect().y()), QSize(rect().width() - expectArea.x(), expectArea.y()));
        outside[2] = QRect(QPoint(expectArea.right() + 1, expectArea.y()), QSize(rect().width() - expectArea.right(), expectArea.height()));
        outside[3] = QRect(QPoint(rect().x(), expectArea.bottom() + 1), rect().bottomRight());
    }

    update();
    magn->raise();
}

QImage ScreenShotWidget::getScreenShotImage()
{
    if(drawer){
        return drawer->grab().toImage();
    }
    return image.copy(screenShotArea);
}

void ScreenShotWidget::initToolConnect()
{
    connect(tools, &Tools::draw, [this](int type){
        if(!drawer){
            drawer = new YImageDrawer(getScreenShotImage(), this);
            drawer->setViewCursor(Yuan::CustomCursor());
            drawer->move(screenShotArea.topLeft());
//            setGeometry(screenShotArea);
            drawer->show();
            drawer->setTools(drawTools);
            connect(drawTools, &DrawTools::thicknessChanged, drawer, &YImageDrawer::thicknessChanged);
            connect(drawTools, &DrawTools::colorChanged, drawer, &YImageDrawer::colorChanged);
            connect(drawTools, &DrawTools::fontChanged, drawer, &YImageDrawer::fontChanged);
            connect(drawTools, &DrawTools::vagueChanged, drawer, &YImageDrawer::vagueChanged);
            connect(tools, &Tools::redo, drawer, &YImageDrawer::redo);
            update();
        }
        drawer->setType(type);
        drawTools->set(tools->geometry());
        if(!tools->toped && drawTools->toped){
            QRect rect = screenShotArea;
            rect.setY(rect.y() - drawTools->height() - 5);
            rect.setBottom(tools->getDesktopSize().height());
            tools->set(rect);
            drawTools->set(tools->geometry());
        }
        drawTools->setStackIndex();
        if(type == YImageDrawer::Mosaic){
            drawTools->setStackIndex(1);
        }else if(type == YImageDrawer::Text || type == YImageDrawer::Tip){
            drawTools->setStackIndex(0);
        }
    });
    connect(tools, &Tools::tack, [this]{
        new StickyNote(getScreenShotImage());
    });
    connect(tools, &Tools::record, [this]{
        (new MediaTools)->tack(screenShotArea);
    });
    connect(tools, &Tools::download, [this]{
        if(drawTools)drawTools->unset();
        emit deleteLated();
        QString filename = QFileDialog::getSaveFileName(nullptr, "保存", "D:/Temp/未命名.jpg", "(*.jpg);;(*.png)");
        if(filename.isEmpty()) return;
        getScreenShotImage().save(filename);
    });
    connect(tools, &Tools::clipBoard, [this]{
        QClipboard* clipBoard = qApp->clipboard();
        clipBoard->setImage(getScreenShotImage());
    });
    connect(tools, &Tools::finished, this, &ScreenShotWidget::deleteLater);
}

void ScreenShotWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(Qt::NoPen);
    painter.drawImage(rect(), image);
    painter.setBrush(QColor(0, 0, 0, 60));

    if(screenShotArea.isValid()){
        for(const QRect& rect : outside){
            painter.drawRect(rect);
        }

        if(!drawer){
            if(!pressed){
                painter.setBrush(QColor(0, 255, 255));
                for(const QRect& rect : edge){
                    painter.drawRect(rect);
                }
                for(const QRect& rect : corner){
                    painter.drawRect(rect);
                }
            }

            painter.setPen(QPen(QColor(0, 255, 255)));
            painter.setBrush(Qt::NoBrush);
            painter.drawRect(screenShotArea);
        }
    }else if(expectArea.isValid()){
        for(const QRect& rect : outside){
            painter.drawRect(rect);
        }
        painter.setPen(QPen(QColor(0, 255, 255)));
        painter.setBrush(Qt::NoBrush);
        painter.drawRect(expectArea);
    }else{
        painter.drawRect(rect());
    }
}

void ScreenShotWidget::mousePressEvent(QMouseEvent *mouseEvent)
{
    if(mouseEvent->button() == Qt::RightButton) return;
    if(drawer){
        return;
    }
    pressed = true;
    moveEdgeState = 0;
    switch(currentState){
        case Left: {
            moveEdgeState = Qt::Horizontal;
            pressPoint.setX(screenShotArea.right());
        }break;
        case Right: {
            moveEdgeState = Qt::Horizontal;
            pressPoint.setX(screenShotArea.x());
        }break;
        case Top: {
            moveEdgeState = Qt::Vertical;
            pressPoint.setY(screenShotArea.bottom());
        }break;
        case Bottom: {
            moveEdgeState = Qt::Vertical;
            pressPoint.setY(screenShotArea.y());
        }break;
        case TopLeft: pressPoint = screenShotArea.bottomRight(); break;
        case TopRight: pressPoint = screenShotArea.bottomLeft(); break;
        case BottomLeft: pressPoint = screenShotArea.topRight(); break;
        case BottomRight: pressPoint = screenShotArea.topLeft(); break;
        case Center: {
            moveEdgeState = 3;
            moveTopLeftPoint = screenShotArea.topLeft();
        } [[clang::fallthrough]];
        default: pressPoint = mouseEvent->pos(); break;
    }

}

void ScreenShotWidget::mouseMoveEvent(QMouseEvent *mouseEvent)
{
    if(drawer){
        return;
    }
//    QColor color = magn->image.pixelColor(mouseEvent->x(), mouseEvent->y());
    QPoint pos = mouseEvent->pos();
    if(pressed){
        if(!moveEdgeState){
            screenShotArea.setTopLeft(QPoint(qMin(pressPoint.x(), pos.x()), qMin(pressPoint.y(), pos.y())));
            screenShotArea.setBottomRight(QPoint(qMax(pressPoint.x(), pos.x()), qMax(pressPoint.y(), pos.y())));
            magn->set(QCursor::pos());
        }else if(moveEdgeState == Qt::Horizontal){
            screenShotArea.setX(qMin(pressPoint.x(), pos.x()));
            screenShotArea.setRight(qMax(pressPoint.x(), pos.x()));
        }else if(moveEdgeState == Qt::Vertical){
            screenShotArea.setY(qMin(pressPoint.y(), pos.y()));
            screenShotArea.setBottom(qMax(pressPoint.y(), pos.y()));
        }else{
            QPoint changePos = moveTopLeftPoint - pressPoint + pos;
            if(changePos.x() < 0) { changePos.setX(0); }
            else if(changePos.x() + screenShotArea.width() > width()) { changePos.setX(width() - screenShotArea.width()); }
            if(changePos.y() < 0) { changePos.setY(0); }
            else if(changePos.y() + screenShotArea.height() > height()) { changePos.setY(height() - screenShotArea.height()); }
            if(changePos != screenShotArea.topLeft()){
                screenShotArea.moveTo(changePos);
            }
        }
        refreshScreenShotArea();
    }else{
        if(screenShotArea.isValid()){
            Qt::CursorShape cursor = Qt::BusyCursor;
            currentState = None;
            if(corner[0].contains(pos)) {
                currentState = TopLeft;
                cursor = Qt::SizeFDiagCursor;
            } else if(corner[1].contains(pos)) {
                cursor = Qt::SizeBDiagCursor;
                currentState = TopRight;
            } else if(corner[2].contains(pos)) {
                cursor = Qt::SizeBDiagCursor;
                currentState = BottomLeft;
            } else if(corner[3].contains(pos)) {
                cursor = Qt::SizeFDiagCursor;
                currentState = BottomRight;
            } else if(edge[0].contains(pos)) {
                cursor = Qt::SizeVerCursor;
                currentState = Top;
            } else if(edge[1].contains(pos)) {
                cursor = Qt::SizeVerCursor;
                currentState = Bottom;
            } else if(edge[2].contains(pos)) {
                cursor = Qt::SizeHorCursor;
                currentState = Left;
            } else if(edge[3].contains(pos)) {
                cursor = Qt::SizeHorCursor;
                currentState = Right;
            } else if(screenShotArea.contains(pos)){
                cursor = Qt::SizeAllCursor;
                currentState = Center;
            }
            if(currentState != None){
                setCursor(cursor);
            }else{
                setCursor(Yuan::CustomCursor());
            }
        }else{
            bool changed = false;
            QPoint pos = QCursor::pos();
            if(expectArea.isValid() && expectArea.contains(pos)){
                QRect rect = Yuan::validRect();
                if(rect.isValid() && rect != expectArea){
                    expectArea = rect;
                    changed = true;
                }
            }else if(!expectArea.isValid() || !expectArea.contains(pos)){
                expectArea = Yuan::validRect();
                changed = true;
            }
            if(changed && expectArea.isValid()){
                if(!image.rect().contains(expectArea)){
                    if(expectArea.x() < 0) expectArea.setX(0);
                    if(expectArea.y() < 0) expectArea.setY(0);
                    if(expectArea.right() > image.width()) expectArea.setRight(image.width());
                    if(expectArea.bottom() > image.height()) expectArea.setBottom(image.height());
                }
                refreshScreenShotArea();
            }
            magn->set(pos);
        }
    }
}

void ScreenShotWidget::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
    if(mouseEvent->button() == Qt::RightButton){
        if(screenShotArea.isValid()){
            screenShotArea = QRect();
            refreshScreenShotArea();
            tools->unset();
            drawTools->unset();
            if(drawer){
                drawer->deleteLater();
                drawer = nullptr;
            }
        }else{
            this->deleteLater();
        }
    }else if(!drawer){
        pressed = false;
        update();
        if(!screenShotArea.isValid() && expectArea.isValid() && mouseEvent->pos() == pressPoint){
            screenShotArea = expectArea;
            refreshScreenShotArea();
            magn->unset();
        }
        if(screenShotArea.isValid()){
            magn->unset();
            tools->set(screenShotArea);
        }else{
            tools->unset();
            drawTools->unset();
        }
    }
}

void ScreenShotWidget::focusOutEvent(QFocusEvent *)
{
    if(tools->isHidden())
        this->deleteLater();
}

void ScreenShotWidget::keyReleaseEvent(QKeyEvent *keyEvent)
{
    switch (keyEvent->key()){
        case Qt::Key_C: {
            qApp->clipboard()->setText(QString("%1, %2, %3").arg(magn->currentColor.red())
                                       .arg(magn->currentColor.green()).arg(magn->currentColor.blue()));
        }break;
        case Qt::Key_Escape: this->deleteLater(); break;
        default: break;
    }
}
